

#ifndef _IMAGE_BUFFER_
#define	_IMAGE_BUFFER_


#ifndef QT_CORE_LIB
	#include <boost\thread.hpp>
#else 
	#include <QMutex>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <CxType.hpp>
#include <opencv2/opencv.hpp>
#include <QTime>


namespace _Detail{

typedef     struct tagImageData
{
	uchar	*data;
	uint	width;
	uint	height;

    tagImageData(uint _width=0,uint _height=0):width(_width),height(_height)
	{
		data=(uchar*)malloc(width*height*3+32);
	}

	~tagImageData()
	{
	}

	void		realloc_data(uint _width,uint _height)
	{
		if((_width*_height)		<	(height*width))
			return ;

		width=_width;
		height=_height;

        if((data = (uchar*)realloc(data,_width*_height*4))==NULL)
				CX_ASSERT_MSG(0,"have no memery");
	}


	bool		isNull()const
	{
        return	(width==0	&&	height==0)?true:false;
	}

	void		release()
	{
		free(data);
	}

}_imageData;

}

typedef     class      tagImageData
{

public:
    tagImageData(){}
    ~tagImageData(){}

public:

    void		importData(uchar *_data,uint _width,uint _height,uint color)
    {
        imageData.realloc_data(_width,_height);
        toRGB(_data,color);
    }

protected:

    void        toRGB(uchar *_data,uint color)
    {
        QTime time;
        switch(color)
        {
        case DC1394_COLOR_CODING_MONO8:

            time.start();
            MONO_to_RGB(_data,true);
            //std::cout<<"Conver:"<<time.elapsed()<<std::endl;

            break;
        case DC1394_COLOR_CODING_MONO16:
            MONO_to_RGB(_data,false);
            break;
        case DC1394_COLOR_CODING_RGB8:
            RGB_to_RGB(_data);
            //time.start();
            //memcpy(imageData.data,_data,imageData.height*imageData.width*3);
            //std::cout<<"Conver:"<<time.elapsed()<<std::endl;
            break;
        case DC1394_COLOR_CODING_YUV422:

            time.start();
			YUV422_to_RGB(_data);
            //std::cout<<"Conver:"<<time.elapsed()<<std::endl;

            break;
        }
    }


    void        MONO_to_RGB(uchar *_data,bool     is_8)
    {
        int j=-1;
        if(is_8)
        {

            for(int i=0;i<imageData.height*imageData.width;++i)
            {               
                imageData.data[++j]=_data[i];
                imageData.data[++j]=_data[i];
                imageData.data[++j]=_data[i];
                imageData.data[++j]=255;
            }
        }
        else
        {
            for(int i=0;i<imageData.height*imageData.width*2;++i)
            {

                imageData.data[++j]=_data[i+1];
                imageData.data[++j]=_data[i+1];
                imageData.data[++j]=_data[i+1];
                imageData.data[++j]=255;
            }
        }
    }

    void        RGB_to_RGB(uchar *_data)
    {
        int j=0;
        for(int i=0;i<imageData.height*imageData.width*3;)
        {
            imageData.data[++j]=_data[++i];
            imageData.data[++j]=_data[++i];
            imageData.data[++j]=_data[++i];
            imageData.data[++j]=255;
        }

    }

    void        YUV422_to_RGB(uchar *_data )
    {

        int  Y,U,V,R,G,B;
        uchar *yuv;
        long i=0;

        for(int y=0;y<imageData.height;++y)
        {
            for(int x=0;x<imageData.width*2;x+=4)
            {
                yuv=_data+imageData.width*2*y+x;


                Y=yuv[1];
                U=yuv[0];
                V=yuv[2];

                R=Y+((360*(V-128))>>8);
                G=Y-((88*(U-128))>>8)-((183*(V-128))>>8);
                B=Y+((455*(U-128))>>8);

                *(imageData.data+i)=R > 255 ? 255 : R;
                *(imageData.data+i+1)=G > 255 ? 255 : G;
                *(imageData.data+i+2)=B > 255 ? 255 : B;
                *(imageData.data+i+3)=255;
                i+=4;

                Y=yuv[3];

                R=Y+((360*(V-128))>>8);
                G=Y-((88*(U-128))>>8)-((183*(V-128))>>8);
                B=Y+((455*(U-128))>>8);

                *(imageData.data+i)=R > 255 ? 255 : R;
                *(imageData.data+i+1)=G > 255 ? 255 : G;
                *(imageData.data+i+2)=B > 255 ? 255 : B;
                *(imageData.data+i+3)=255;
                i+=4;

            }
        }
   }

public:


    uchar       *data()
    {
        return  imageData.data;
    }
    uint        width()const
    {
        return  imageData.width;
    }
    uint        height()const
    {
        return  imageData.height;
    }
    bool        isNull() const
    {
        return  imageData.isNull();
    }

    void        release()
    {
        imageData.release();
    }

private:

    _Detail::_imageData         imageData;

}_imageData;



template<uint N>
class	CxImageBuffer
{
public:
	CxImageBuffer():currentCap(0),writePointer(0),readPointer(0)
	{
	}
	~CxImageBuffer()
	{
		for(int i=0;i<N;++i)
			data[i].release();
	}

public:

#ifndef QT_CORE_LIB
	typedef		boost::mutex				_Mutex;
	typedef		boost::mutex::scoped_lock	_Locker;
	#define		__Lock(mu)		_Locker	locker(mu)

#else 
	typedef		QMutex						_Mutex;
	typedef		QMutexLocker				_Locker;
	#define		__Lock(mu)		_Locker	locker(&mu)
#endif


public:
	
    void		push_image(uchar *_data,uint	_width,uint	_height,uint color)
	{
        __Lock(mu);

        data[writePointer].importData(_data,_width,_height,color);
		update_write_pointer();
	}

	_imageData	pop_image()
	{
        __Lock(mu);

        if(size()==0)
            return _imageData();

		_imageData	tmpdata=data[readPointer];
		update_read_pointer();
		return tmpdata;
	}

	uint		size()const
	{
		return	currentCap;
	}

#ifndef     NDEBUG
	void		print()
	{
		__Lock(mu);

		DEBUG_PRINT<<"writePointer:"<<writePointer<<'\t'<<
			"readPointer:"<<readPointer<<'\t'<<
			"cap	:"<<currentCap<<PRINT_END;
	}
#else
    void        print(){}
#endif

protected:

	/*	update write pointer */
	void		update_write_pointer()
	{
		if(++currentCap		>=	N)
		{
			currentCap	=	N;
			if(++writePointer	==	N)
				writePointer	=	0;

			readPointer =	writePointer + 1;

			if(readPointer	==	N)
				readPointer	=	0;
		}
		else 
		{
			if(++writePointer	==	N)
				writePointer	=	0;
		}
	}

	/*	update read pointer */
	void		update_read_pointer()
	{
		if(currentCap	==	0)
			return ;
		else 
		{
			--currentCap;
			if(++readPointer	==	N)
				readPointer		=	0;
		}
	}

private:

	volatile		uint	currentCap;
	volatile		uint	readPointer;
	volatile		uint	writePointer;



	_Mutex			mu;
	_imageData		data[N];
};




#endif

